﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace iRCL_Crypt
{
    public class SongFile
    {
        private static readonly UInt32 FILE_HEADER = 0x010C0501;
        private String _filename;
        private SongInfo _songinfo;
        private UInt32 _start;
        private byte[] _buffer;
        public SongFile()
        {
            _filename = null;
            _songinfo = null;
            _start = 0;
            _buffer = null;
        }
        public String FileName
        {
            get
            {
                return _filename;
            }
            set
            {
                _filename = value;
            }
        }
        public SongInfo SongInfo
        {
            get
            {
                return _songinfo;
            }
            set
            {
                if ((_songinfo == null) || _songinfo.AreLengthsDifferent(value))
                    _start = 0;
                _songinfo = value;
            }
        }
        public byte[] Buffer
        {
            get
            {
                return _buffer;
            }
            set
            {
                _buffer = value;
            }
        }
        public bool IsFileReady()
        {
            return (_filename != null) && (System.IO.File.Exists(_filename));
        }
        public bool IsInfoReady()
        {
            return (null != _songinfo);
        }
        public bool IsBufferReady()
        {
            return (null != _buffer);
        }
        public bool IsReady()
        {
            return (null != _filename) &&
                   (null != _songinfo) &&
                   (null != _buffer);
        }
        public void ClearBuffer()
        {
            _buffer = null;
        }
        public bool LoadHeaders(bool force)
        {
            if ((_songinfo != null) && !force)
                return true;
            BinaryReader reader = null;
            try
            {
                FileStream f = File.Open(_filename, FileMode.Open, FileAccess.Read);
                f.Seek(0, SeekOrigin.Begin);
                reader = new BinaryReader(f);
                UInt32 header = reader.ReadUInt32();
                if (header != FILE_HEADER)
                {
                    return false;
                }
                UInt16 len = 0;
                // TODO: Add Decryption Code!
                _songinfo = new SongInfo();
                _songinfo.track = reader.ReadUInt16();
                _songinfo.disk = reader.ReadUInt16();
                _songinfo.compilation = reader.ReadByte() != 0;
                len = reader.ReadUInt16();
                _songinfo.album = new String(reader.ReadChars(len));
                len = reader.ReadUInt16();
                _songinfo.author = new String(reader.ReadChars(len));
                len = reader.ReadUInt16();
                _songinfo.title = new String(reader.ReadChars(len));
                len = reader.ReadUInt16();
                _songinfo.date = new String(reader.ReadChars(len));
                len = reader.ReadUInt16();
                _songinfo.genre = new String(reader.ReadChars(len));
                //_songinfo.cover
                _start = (UInt32)f.Position;
                reader.Close();
                return true;
            }
            catch (IOException)
            {
                if (reader != null)
                    reader.Close();
                _songinfo.Dispose();
                _songinfo = null;
                _start = 0;
            }
            return false;
        }
        public bool LoadBuffer(bool force)
        {
            if ((_songinfo != null) && (_buffer != null) && !force)
                return true;
            if (!IsInfoReady() || (_start == 0))
            {
                if (!LoadHeaders(force))
                {
                    return false;
                }
            }
            BinaryReader reader = null;
            try
            {
                FileStream f = File.Open(_filename, FileMode.Open, FileAccess.Read);
                f.Seek(_start, SeekOrigin.Begin);
                reader = new BinaryReader(f);
                // TODO: Add Decryption Code!
                UInt32 len = reader.ReadUInt32();
                _buffer = reader.ReadBytes((int)len);
                reader.Close();
                return true;
            }
            catch (IOException)
            {
                if(reader != null)
                    reader.Close();
                _songinfo.Dispose();
                _songinfo = null;
                _start = 0;
                _buffer = null;
            }
            return false;
        }
        public bool Load()
        {
            return LoadHeaders(false) && LoadBuffer(false);
        }
        public bool Save()
        {
            if (!IsReady())
            {
                if (!IsInfoReady() || !IsFileReady() || !LoadBuffer(false))
                {
                    return false;
                }
            }
            BinaryWriter writer = null;
            try
            {
                FileStream f = File.Open(_filename, FileMode.Create, FileAccess.Write);
                f.Seek(0, SeekOrigin.Begin);
                writer = new BinaryWriter(f);
                writer.Write(FILE_HEADER);
                UInt16 len = 0;
                // TODO: Add Encryption Code!
                writer.Write(_songinfo.track);
                writer.Write(_songinfo.disk);
                writer.Write(_songinfo.compilation);
                len = (UInt16)_songinfo.album.Length;
                writer.Write(len);
                writer.Write(_songinfo.album.ToCharArray());
                len = (UInt16)_songinfo.author.Length;
                writer.Write(len);
                writer.Write(_songinfo.author.ToCharArray());
                len = (UInt16)_songinfo.title.Length;
                writer.Write(len);
                writer.Write(_songinfo.title.ToCharArray());
                len = (UInt16)_songinfo.date.Length;
                writer.Write(len);
                writer.Write(_songinfo.date.ToCharArray());
                len = (UInt16)_songinfo.genre.Length;
                writer.Write(len);
                writer.Write(_songinfo.genre.ToCharArray());
                //_songinfo.cover
                UInt32 buflen = (UInt32)_buffer.Length;
                writer.Write(buflen);
                writer.Write(_buffer);
                writer.Close();
                return true;
            }
            catch (IOException)
            {
                if(writer != null)
                    writer.Close();
                _songinfo.Dispose();
                _songinfo = null;
                _start = 0;
            }
            return false;
        }
    }
}
